use std::fs;
use tracing::warn;
use crate::config::{Config, Mapping};
use tracing::info;
use crate::{daemon, sync};
use crate::cli::{ConfigAction, DaemonAction};
use anyhow::{Context, Result};
use std::process::Command;
use tempfile::NamedTempFile;
use std::io::Write;
use crate::sync::Direction;
use dialoguer::{Confirm, Input};
use std::path::PathBuf;
use crate::utils::collect_patterns;
pub fn handle_init(force : &bool) -> Result<()> {
    Config::init_config(*force)
        .context("初始化配置文件失败")?;
    Ok(())
}

pub fn handle_push(name : &Option<String> , delete_source : &bool) -> Result<()> {
    let config = Config::load().context("加载配置文件失败")?;
    let mapping = match name {
        Some(name) => config.find_mapping_by_name(name)
            .with_context(|| format!("未找到映射: {}", name))?,
        None => config.find_mapping_by_current_dir()?
            .with_context(|| "当前目录不在任何映射的源路径中")?,
    };
    sync::sync(&mapping, sync::Direction::Push, *delete_source)?;
    Ok(())
}

pub fn handle_pull(name : &String , delete : &bool) -> Result<()> {
    let config = Config::load().context("加载配置文件失败")?;
    let mapping = config.find_mapping_by_name(name)
        .with_context(|| format!("未找到映射: {}", name))?;
    sync::sync(&mapping, sync::Direction::Pull, false )?;  // pull 不会删除外部硬盘的备份
    Ok(())
}


pub fn handle_remove(name : &str) -> Result<()> {
    let mut config = Config::load()
        .context("删除映射失败，无法加载配置文件，请尝试先执行ice init")?;
    let origin_count = config.mappings.len() ;

    config.mappings.retain(|mapping | mapping.name != name) ;
    let new_count = config.mappings.len() ;

    if origin_count ==  new_count {
        warn!("未找到名称为{name}的映射，请使用ice list检查所有映射") ;
        return Ok(()) ;
    }
    config.save()
        .context("删除映射失败，无法写回配置文件")? ;
    info!("已经成功删除了{name}映射,现在还有{new_count}个映射") ;
    Ok(())
}

pub fn handle_list() -> Result<()> {
    let config = Config::load().context("加载配置文件失败")?;   // list是一种只读  不计入日志
    for mapping in &config.mappings {
        println!(
            "{}: {} -> {}",
            mapping.name,
            mapping.source.display(),
            mapping.destination.display()
        );
    }
    Ok(())
}


pub fn handle_daemon(action : &DaemonAction) -> Result<()> {
    // 统一创建 Daemon 实例（使用默认路径或从配置读取）
    let pid_path =  dirs::home_dir()
        .context("无法找到用户主目录")
        .map(|home| home.join(".ice").join("daemon.pid"))?;
    let config_path = Config::config_path()? ;
    let config = Config::load().context("加载配置文件失败")?;
    let interval = config.global.daemon_scan_interval.unwrap_or(60);
    let daemon = daemon::Daemon::new(
        pid_path ,
        config_path,
        interval,
    );

    match action {
        DaemonAction::Start => daemon.start()?,
        DaemonAction::Stop => daemon.stop()?,
        DaemonAction::Status => daemon.status()?,
        DaemonAction::Run => {
            // 这里用 tokio 运行异步的 run 方法
            let rt = tokio::runtime::Runtime::new()?;
            rt.block_on(daemon.run())?;
        }
    }
    Ok(())
}



pub fn handle_rsync(name: &Option<String>, direction: &str, delete_source : &bool ,dry_run: &bool) -> Result<()> {
    // 1. 读取配置
    let config = crate::config::Config::load()
        .context("读取配置文件失败")?;

    // 2. 找到 mapping
    let mapping = match name {
        Some(name) => config.find_mapping_by_name(name)
            .with_context(|| format!("未找到映射: {}", name))?,
        None => config.find_mapping_by_current_dir()?
            .with_context(|| "当前目录不在任何映射的源路径中")?,
    };

    // 3. 确定源和目标
    let (source, dest) = match direction.to_lowercase().as_str() {
        "push" => (&mapping.source, &mapping.destination),
        "pull" => (&mapping.destination, &mapping.source),
        _ => anyhow::bail!("方向必须是 push 或 pull"),
    };

    // 4. 生成 exclude 文件
    let mut exclude_file = NamedTempFile::new()
        .context("创建临时 exclude 文件失败")?;
    for rule in &mapping.exclude {
        writeln!(exclude_file, "{}", rule)?;
    }
exclude_file.flush()?;


    // 5. 构建 rsync 命令
    let mut cmd = Command::new("rsync");
    cmd.arg("-av")
        .arg("--delete")
        .arg(format!("--exclude-from={}", exclude_file.path().display()))
        .arg(format!("{}/" , source.display()))
        .arg(dest.display().to_string());

    if *dry_run {
        cmd.arg("--dry-run");
    }

    // 6. 执行命令
    let status = cmd.status()
        .context("执行 rsync 失败，请确保系统已安装 rsync")?;

    if !status.success() {
        anyhow::bail!("rsync 执行失败，退出码: {}", status.code().unwrap_or(-1));
    }

    // 复制完成之后 根据额外要求判断是否需要直接删除机载SSD的内容
    if  *delete_source {
        if direction == "push" {
            fs::remove_dir_all(&mapping.source)
                .with_context(|| format!("驱逐成功但删除机载数据失败: {}", mapping.source.display()))?;
            info!("已删除源文件: {}", mapping.source.display());
        }else {
            info!("不允许清楚外部备份, delete_source标志被忽略");
        }
    }
    if !*dry_run {
        info!("rsync执行完毕 {}->{}", mapping.source.display() , mapping.destination.display());
    }
    Ok(())
}

pub fn handle_config(action : &ConfigAction ) -> Result<()> {
    let config_path = crate::config::Config::config_path().context("无法获得配置路径")? ;

    match action {
        ConfigAction::Show => {
            let config = Config::load()? ;
            let toml_str = toml::to_string_pretty(&config)?;
            println!("{}", toml_str);
        } ,
        ConfigAction::Edit => {
            let editor = std::env::var("EDITOR").unwrap_or("vim".to_string());
            let status = Command::new(&editor)
                .arg(&config_path)
                .status()
                .context("启动vim失败")? ;
            if !status.success() {
                anyhow::bail!("编辑器退出异常:{status}");
            }
        }
    }
    Ok(())
}


pub fn handle_add(name : &str) -> Result<()> {
    // 加载现有的配置 查看映射名称是否存在
    let mut config = Config::load()? ;
    if config.has_mapping(name) {
        anyhow::bail!("映射名'{name}'已存在,请更换名称") ;
    }
    eprintln!("\n请输入映射 '{}' 的配置（直接回车使用默认值）", name);
    // 2.1 源目录（必须存在，循环校验）
    let source = loop {
        let input: String = Input::new()
            .with_prompt("源目录（需要同步的文件所在位置）")
            .interact_text()
            .context("获取源目录输入失败")?;
        let path = PathBuf::from(input);
        if path.exists() && path.is_dir() {
            break path;
        } else {
            eprintln!("错误：目录 '{}' 不存在或不是文件夹，请重新输入", path.display());
        }
    };
    // 2.2 目标目录（可不存在，询问是否创建）
    let dest = loop {
        let input: String = Input::new()
            .with_prompt("目标目录（同步的目的地）")
            .interact_text()
            .context("获取目标目录输入失败")?;
        let path = PathBuf::from(input);
        if path.exists() {
            if path.is_dir() {
                break path;
            } else {
                eprintln!("错误：'{}' 不是文件夹，请重新输入", path.display());
            }
        } else {
            let create = Confirm::new()
                .with_prompt(format!("目录 '{}' 不存在，是否创建？", path.display()))
                .default(true)
                .interact()
                .context("确认创建目录失败")?;
            if create {
                std::fs::create_dir_all(&path)
                    .with_context(|| format!("创建目录 '{}' 失败", path.display()))?;
                eprintln!("已创建目录: {}", path.display());
                break path;
            } else {
                eprintln!("请重新输入一个已存在的目录");
            }
        }
    };
    // 2.3 收集 include/exclude 规则（和之前一样，用辅助函数）
    let include = collect_patterns("需要包含的文件/目录（如 *.jpg，空输入结束）")?;
    let exclude = collect_patterns("需要排除的文件/目录（如 *.tmp，空输入结束）")?;



    let ttl = loop {
        let mut input: String = Input::new()
            .with_prompt("生存时间(单位:分钟)")
            .interact_text()
            .context("获取生存时间输入失败")?;
        input = input.trim().to_string();
        if input.is_empty() {
            eprintln!("生存时间不能为空，请重新输入");
            continue ;
        }
        if input == "never" {
            break input ;
        }
        match input.parse::<u32>() {
            Ok(num) => input,
            Err(_) => {
                eprintln!("请输入数字（如 60 表示60分钟）");
                continue;
            }
        };
    };

    // 3. 创建 Mapping 实例（关键：把 name 传入）
    let new_mapping = Mapping {
        name: name.to_string(),  // 这里必须传入映射名
        source : source.clone(),
        destination: dest.clone(),
        include,
        exclude,
        ttl
    };

    // 4. 添加到 Vec 并保存（用 push 替代 HashMap 的 insert）
    config.mappings.push(new_mapping);  // 这里改了！
    config.save()?;

    // 5. 提示成功
    eprintln!("\n✅ 映射 '{}' 添加成功！", name);
    eprintln!("   源目录: {}", source.display());
    eprintln!("   目标目录: {}", dest.display());
    eprintln!("   可用 `ice config` 查看所有映射，或 `ice sync {}` 开始同步", name);

    Ok(())
}

